package com.heima.article.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.heima.article.mapper.ApArticleMapper;
import com.heima.article.service.HotArticleService;
import com.heima.common.constants.message.ArticleConstants;
import com.heima.common.exception.CustException;
import com.heima.feigns.AdminFeign;
import com.heima.model.admin.pojos.AdChannel;
import com.heima.model.article.pojos.ApArticle;
import com.heima.model.article.vos.HotArticleVo;
import com.heima.model.behavior.dtos.AggBehaviorDTO;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.utils.common.DateUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class HotArticleServiceImpl implements HotArticleService {

    @Autowired
    private ApArticleMapper articleMapper;

    @Autowired
    private AdminFeign adminFeign;


    @Autowired
    private StringRedisTemplate redisTemplate;

    @Override
    public void computeHotArticle() {
        // 计算热文章
        // 1. 获取前5天且已上架的文章
        //Date date = new Date();
        // 获取五天前的时间
        SimpleDateFormat fd = new SimpleDateFormat("yyyy-MM-dd 00:00:00");
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.DATE, -5);//当前系统时间的  前一天
        String beginDate = fd.format(calendar.getTime());
        List<ApArticle> articleList = articleMapper.selectArticleByDate(beginDate);
        // 2. 计算每个文章的分值，其中不同的行为设置不同的权重 存入 HotArticleVo
        //（阅读：1，点赞：3，评论：5，收藏：8）
        List<HotArticleVo> hotArticleVoList = getHotArticleVoList(articleList);
        // 3. 获取所有频道,按照不同的频道将文章分类
        ResponseResult<List<AdChannel>> channelsResult = adminFeign.selectChannels();
        if (!channelsResult.checkCode()) {
            CustException.cust(AppHttpCodeEnum.REMOTE_SERVER_ERROR);
        }
        List<AdChannel> channels = channelsResult.getData();
        for (AdChannel channel : channels) {
            List<HotArticleVo> hotArticleVos = hotArticleVoList.stream()
                    .filter(hotArticleVo -> hotArticleVo.getChannelId().equals(channel.getId()))
                    .collect(Collectors.toList());
            // 4. 按照分值排序，给每个频道找出分值较高的30条数据，存入缓存中
            sortAndCache(hotArticleVos, ArticleConstants.HOT_ARTICLE_FIRST_PAGE + channel.getId());
        }
        // 5. 按照分值排序，给全部频道找出分值较高的30条数据，存入缓存中
        sortAndCache(hotArticleVoList, ArticleConstants.HOT_ARTICLE_FIRST_PAGE + ArticleConstants.DEFAULT_TAG);
    }

    @Override
    public void updateApArticle(AggBehaviorDTO aggBehaviorDTO) {
        //1 查询文章
        ApArticle article = articleMapper.selectById(aggBehaviorDTO.getArticleId());
        if (article == null) {
            CustException.cust(AppHttpCodeEnum.DATA_NOT_EXIST);
        }
        //2 修改文章的行为数据（阅读1、点赞3、评论5、收藏8）
        if (aggBehaviorDTO.getView() != 0) {
            article.setViews((int) (article.getViews() == null ? aggBehaviorDTO.getView() : article.getViews() + aggBehaviorDTO.getView()));
        }
        if (aggBehaviorDTO.getLike() != 0) {
            article.setLikes((int) (article.getLikes() == null ? aggBehaviorDTO.getLike() : article.getLikes() + aggBehaviorDTO.getLike()));
        }
        if (aggBehaviorDTO.getComment() != 0) {
            article.setComment((int) (article.getComment() == null ? aggBehaviorDTO.getComment() : article.getComment() + aggBehaviorDTO.getComment()));
        }
        if (aggBehaviorDTO.getCollect() != 0) {
            article.setCollection((int) (article.getCollection() == null ? aggBehaviorDTO.getCollect() : article.getCollection() + aggBehaviorDTO.getCollect()));
        }
        articleMapper.updateById(article);
        //3 计算文章分值
        Integer score = computeScore(article);
        // 如果是今天发布的文章，热度*3      yyyy-MM-dd
        String publishStr = DateUtils.dateToString(article.getPublishTime());
        String nowStr = DateUtils.dateToString(new Date());

        if (publishStr.equals(nowStr)) {
            score = score * 3;
            //当天热点数据 *3
        }
        //4 更新缓存（频道）
        updateArticleCache(article, score, ArticleConstants.HOT_ARTICLE_FIRST_PAGE + article.getChannelId());
        //5 更新推荐列表的缓存
        updateArticleCache(article, score, ArticleConstants.HOT_ARTICLE_FIRST_PAGE + ArticleConstants.DEFAULT_TAG);
    }

    private void updateArticleCache(ApArticle article, Integer score, String cacheKey) {
        boolean flag = false;
        String hotArticleListJson = redisTemplate.opsForValue().get(cacheKey);
        if (StringUtils.isNotBlank(hotArticleListJson)) {
            List<HotArticleVo> hotArticleList = JSONArray.parseArray(hotArticleListJson, HotArticleVo.class);
            //1 如果当前缓存中有当前文章，更新分值
            for (HotArticleVo hotArticleVo : hotArticleList) {
                if (hotArticleVo.getId().equals(article.getId())) {
                    hotArticleVo.setScore(score);
                    flag = true;
                    break;
                }
            }
            if (!flag){
                HotArticleVo hotArticleVo = new HotArticleVo();
                BeanUtils.copyProperties(article, hotArticleVo);
                hotArticleVo.setScore(score);
                hotArticleList.add(hotArticleVo);
            }
            sortAndCache(hotArticleList,cacheKey);
        }
    }

    private void sortAndCache(List<HotArticleVo> hotArticleVoList, String cacheKey) {
        List<HotArticleVo> hotArticleVos = hotArticleVoList.stream()
                .sorted(Comparator.comparing(HotArticleVo::getScore).reversed())
                .limit(30)
                .collect(Collectors.toList());
        redisTemplate.opsForValue().set(cacheKey, JSON.toJSONString(hotArticleVos));
    }

    /**
     * 计算热点文章的分值
     * （阅读：1，点赞：3，评论：5，收藏：8）
     *
     * @param articleList
     * @return
     */
    private List<HotArticleVo> getHotArticleVoList(List<ApArticle> articleList) {
        List<HotArticleVo> hotArticleVoList = new ArrayList<>();
        for (ApArticle article : articleList) {
            HotArticleVo hotArticleVo = new HotArticleVo();
            BeanUtils.copyProperties(article, hotArticleVo);
            Integer score = computeScore(article);
            hotArticleVo.setScore(score);
            hotArticleVoList.add(hotArticleVo);
        }
        return hotArticleVoList;
    }

    private Integer computeScore(ApArticle article) {
        Integer score = 0;
        // 阅读 1
        if (article.getViews() != null) {
            score += article.getViews();
        }
        // 点赞 3
        if (article.getLikes() != null) {
            score += article.getLikes() * 3;
        }
        // 评论 5
        if (article.getComment() != null) {
            score += article.getComment() * 5;
        }
        // 收藏 8
        if (article.getCollection() != null) {
            score += article.getCollection() * 8;
        }
        return score;
    }
}
